﻿using System;
using System.Collections.Generic;
using Microsoft.AspNetCore.Identity;
using Microsoft.Extensions.Logging;
using Microsoft.Extensions.Options;
using Abp.Authorization;
using Abp.Authorization.Users;
using Abp.Configuration;
using Abp.Domain.Repositories;
using Abp.Domain.Uow;
using Abp.Organizations;
using Abp.Runtime.Caching;
using ABCNet.Authorization.Roles;
using System.Threading.Tasks;
using ABCNet.UserFinancialLists;
using ABCNet.PlatformFinancialLists;
using Abp.Localization;
using Abp.Zero;

namespace ABCNet.Authorization.Users
{
    public class UserManager : AbpUserManager<Role, User>
    {
        protected readonly IRepository<User, long> _repository;
        private readonly IRepository<UserFinancialList> _userFinancialRepository;
        private readonly IRepository<PlatformFinancialList> _platformFinancialRepository;
        private readonly IRepository<PlatformInfos.PlatformInfo> _platformInfoRepository;
        private readonly IUnitOfWorkManager _unitOfWorkManager;

        public UserManager(
            RoleManager roleManager,
            UserStore store, 
            IOptions<IdentityOptions> optionsAccessor, 
            IPasswordHasher<User> passwordHasher, 
            IEnumerable<IUserValidator<User>> userValidators, 
            IEnumerable<IPasswordValidator<User>> passwordValidators,
            ILookupNormalizer keyNormalizer, 
            IdentityErrorDescriber errors, 
            IServiceProvider services, 
            ILogger<UserManager<User>> logger, 
            IPermissionManager permissionManager, 
            IUnitOfWorkManager unitOfWorkManager, 
            ICacheManager cacheManager, 
            IRepository<OrganizationUnit, long> organizationUnitRepository, 
            IRepository<UserOrganizationUnit, long> userOrganizationUnitRepository, 
            IOrganizationUnitSettings organizationUnitSettings, 
            ISettingManager settingManager,
            IRepository<User, long> repository,
            IRepository<UserFinancialList> userFinancialRepository,
            IRepository<PlatformFinancialList> platformFinancialRepository,
            IRepository<PlatformInfos.PlatformInfo> platformInfoRepository)
            : base(
                roleManager, 
                store, 
                optionsAccessor, 
                passwordHasher, 
                userValidators, 
                passwordValidators, 
                keyNormalizer, 
                errors, 
                services, 
                logger, 
                permissionManager, 
                unitOfWorkManager, 
                cacheManager,
                organizationUnitRepository, 
                userOrganizationUnitRepository, 
                organizationUnitSettings, 
                settingManager)
        {
            _repository = repository;
            _userFinancialRepository = userFinancialRepository;
            _platformFinancialRepository = platformFinancialRepository;
            _platformInfoRepository = platformInfoRepository;
            _unitOfWorkManager = unitOfWorkManager;
        }

        #region 重新登陆


        public override async Task<IdentityResult> CheckDuplicateUsernameOrEmailAddressAsync(long? expectedUserId, string userName, string emailAddress)
        {
            var user = (await FindByNameAsync(userName));
            if (user != null && user.Id != expectedUserId)
            {
                string msg = string.Format(L("Identity.DuplicateName"), userName);
                return IdentityResult.Failed(new IdentityError() { Description = msg, Code = "500" });
            }
            return IdentityResult.Success;
        }

        private string L(string name)
        {
            return LocalizationManager.GetString(AbpZeroConsts.LocalizationSourceName, name);
        }

        public override async Task<IdentityResult> CreateAsync(User user)
        {
            var result = await CheckDuplicateUsernameOrEmailAddressAsync(user.Id, user.UserName, user.EmailAddress);
            if (!result.Succeeded)
            {
                return result;
            }

            user.EmailAddress = string.Empty;

            var tenantId = GetCurrentTenantId();
            if (tenantId.HasValue && !user.TenantId.HasValue)
            {
                user.TenantId = tenantId.Value;
            }

            try
            {
                return await base.CreateAsync(user);
            }
            catch (Exception e)
            {
                Console.WriteLine(e);
                throw;
            }

        }

        private int? GetCurrentTenantId()
        {
            if (_unitOfWorkManager.Current != null)
            {
                return _unitOfWorkManager.Current.GetTenantId();
            }

            return AbpSession.TenantId;
        }

        #endregion

        public void Recharge(User user, bool isKoufei, decimal value)
        {
            value = isKoufei ? -value : value;

            //记录历史
            var ufl = new UserFinancialList
            {
                ChangedAmount = value,
                UserId = user.Id,
                UBusinessType = isKoufei ? UBusinessTypes.用户扣费 : UBusinessTypes.用户充值,
                UBusinessTypeName = isKoufei ? nameof(UBusinessTypes.用户扣费) : nameof(UBusinessTypes.用户充值),
                BeforeChangedAmount = user.AvailableBalance,
                AfterChangedAmount = user.AvailableBalance + value
            };
            _userFinancialRepository.InsertAndGetId(ufl);
            //充值而用余额
            _repository.Update(user.Id, x => x.AvailableBalance += value);
        }


        public void Transfer(User currentUser, User targetUser, int transferAmount)
        {
            //扣减登陆人，记录历史
            var ufl1 = new UserFinancialList
            {
                ChangedAmount = -transferAmount,
                UserId = currentUser.Id,
                UBusinessType = UBusinessTypes.用户转账,
                UBusinessTypeName = nameof(UBusinessTypes.用户转账),
                BeforeChangedAmount = currentUser.AvailableBalance,
                AfterChangedAmount = currentUser.AvailableBalance - transferAmount,
                TradingUserId = targetUser.Id
            };
            _userFinancialRepository.InsertAndGetId(ufl1);
            _repository.Update(currentUser.Id, x => x.AvailableBalance -= transferAmount);

            //转账目标用户,记录历史
            var ufl2 = new UserFinancialList
            {
                ChangedAmount = transferAmount,
                UserId = targetUser.Id,
                UBusinessType = UBusinessTypes.用户转账,
                UBusinessTypeName = nameof(UBusinessTypes.用户转账),
                BeforeChangedAmount = targetUser.AvailableBalance,
                AfterChangedAmount = targetUser.AvailableBalance + transferAmount,
                TradingUserId = currentUser.Id
            };
            _userFinancialRepository.InsertAndGetId(ufl2);
            _repository.Update(targetUser.Id, x => x.AvailableBalance += transferAmount);
        }

    }
}
